// ----------------------------------------------------------------------------
// serialize_string_pointer_member.cpp
// ----------------------------------------------------------------------------
#include <fw/base/serialize/serialize_string_pointer_member.h>
#include <fw/base/serialize/serialize_type.h>
#include <fw/base/serialize/serialize_pointer_value.h>
#include <fw/base/serialize/byte_reader.h>
#include <fw/base/serialize/byte_writer.h>

namespace fw
{
	SerializeStringPointerMember::SerializeStringPointerMember(int							count,
															   Hash							typeName,
															   Hash							terminatorName,
															   const SerializeScalarValue&	terminatorValue)
	: SerializePointerMember(count, typeName)
	{
		m_terminatorValue = terminatorValue;
		m_terminatorName  = terminatorName;
	}
	
	int SerializeStringPointerMember::GetPointerCount(const char *scopeData, int index) const
	{
		const char* memberData = GetDataPtr(scopeData, index);
		
		const SerializePointerType* pointerType = GetType()->AsPointerType();
		FW_ASSERT(pointerType);
		FW_ASSERT(pointerType->GetIndirectType());
		SerializePointerValue value = pointerType->ReadPointerValue(memberData);
		
		int stringCount = 0;
		const char* p = value.AsConstCharStar();
		bool terminated = false;
		while(!terminated)
		{
			stringCount++;
			terminated = pointerType->GetIndirectType()->IsTerminal(p, m_terminatorValue, m_terminatorName);
			p         += pointerType->GetIndirectType()->GetSize();
		}
		return stringCount;
	}
	
	void SerializeStringPointerMember::Write(ByteWriter &writer) const
	{
		uint8_t code = kByteCode_StringPointer;
		
		if(GetCount()>1)
		{
			code |= kByteCodeFlag_Array;
		}
		if(m_terminatorName)
		{
			code |= kByteCodeFlag_TermName;
		}
		if(!m_terminatorValue.IsZero())
		{
			code |= kByteCodeFlag_TermValue;
		}
		
		writer.Write8	(code);
		writer.Write32	(GetTypeName());
		
		if(code & kByteCodeFlag_Array)
		{
			writer.Write16(GetCount());
		}
		if(code & kByteCodeFlag_TermName)
		{
			writer.Write32(m_terminatorName);
		}
		if(code & kByteCodeFlag_TermValue)
		{
			writer.Write(&m_terminatorValue);
		}
	}
	
	SerializeStringPointerMember* SerializeStringPointerMember::ReadNew(ByteReader &reader)
	{
		size_t rollBack = reader.Tell();
		SerializeStringPointerMember* member = nullptr;
		
		uint8_t code = reader.Read8();
		
		if((code & kByteCode_Mask) == kByteCode_StringPointer)
		{
			int count = 1;
			Hash					terminatorName;
			SerializeScalarValue	terminatorValue;
			
			Hash typeName = reader.Read32();
			if(code & kByteCodeFlag_Array)
			{
				count = reader.Read16();
			}
			if(code & kByteCodeFlag_TermName)
			{
				terminatorName = reader.Read32();
			}
			if(code & kByteCodeFlag_TermValue)
			{
				terminatorValue = reader.Read<SerializeScalarValue>();
			}
			member = new SerializeStringPointerMember(count, typeName, terminatorName, terminatorValue);
		}
		if(!member)
		{
			reader.Seek(rollBack);
		}
		return member;
	}
	
	uint64_t SerializeStringPointerMember::GetChecksum(uint64_t basis) const
	{
		basis = SerializeMember::GetChecksum(basis);
		basis = HashValue64(m_terminatorName, basis);
		basis = m_terminatorValue.GetChecksum(basis);
		return basis;
	}
	
} // namespace fw
